package com.jinzhi.jzweb.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.jinzhi.common.base.CoreServiceImpl;
import com.jinzhi.common.service.DictService;
import com.jinzhi.common.utils.Result;
import com.jinzhi.common.utils.StringUtil;
import com.jinzhi.jzapi.training.pojo.CoursesAndTeacherVo;
import com.jinzhi.jzapi.training.pojo.CoursesListVo;
import com.jinzhi.jzweb.dao.CoursesDao;
import com.jinzhi.jzweb.domain.ChapterDO;
import com.jinzhi.jzweb.domain.ConsultationsDO;
import com.jinzhi.jzweb.domain.CoursesDO;
import com.jinzhi.jzweb.pojo.entity.ChapterDocument;
import com.jinzhi.jzweb.pojo.entity.Records;
import com.jinzhi.jzweb.pojo.request.CouresesRequest;
import com.jinzhi.jzweb.service.*;
import com.jinzhi.jzweb.utils.ZipFileUtils;
import com.jinzhi.oss.controller.MinIoController;
import com.jinzhi.sys.domain.UserDO;
import com.jinzhi.sys.service.UserService;
import org.apache.poi.ss.usermodel.Workbook;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 
 * <pre>
 * 课程表
 * </pre>
 * <small> 2020-02-24 21:00:12 | lance</small>
 */
@Service
public class CoursesServiceImpl extends CoreServiceImpl<CoursesDao, CoursesDO> implements CoursesService {

    private final ChapterDocumentService chapterDocumentService;

    private final UserService userService;

    @Autowired
    private MinIoController minIoController;

    private final ChapterService chapterService;

    private final DictService dictService;

    private final RecordsService recordsService;

    private final ConsultationsService consultationsService;

    public CoursesServiceImpl(ChapterDocumentService chapterDocumentService, UserService userService, ChapterService chapterService, DictService dictService, RecordsService recordsService,ConsultationsService consultationsService) {
        this.chapterDocumentService = chapterDocumentService;
        this.userService = userService;
        this.chapterService = chapterService;
        this.dictService = dictService;
        this.recordsService = recordsService;
        this.consultationsService = consultationsService;
    }

    @Override
    public Page<CoursesListVo> selectListPage(int current, int number, Map map) {

        // 新建分页
        Page<CoursesListVo> page = new Page<CoursesListVo>(current, number);
        return page.setRecords(this.baseMapper.dyGetUserList(page,map));
    }

    @Override
    public CoursesAndTeacherVo selCourseDetail(Long id){
        return this.baseMapper.selCourseDetail(id);
    }

    @Override
    public List<Map> selCourseList(Map map){
        return this.baseMapper.selCourseList(map);
    }

    @Override
    public List<Map> selAllCourseList(){
        return this.baseMapper.selAllCourseList();
    }

    @Override
    public List<Long> selCoursesIdList(Map map){
        return this.baseMapper.selCoursesIdList(map);
    }


    @Override
    public Result getCourseList(CouresesRequest request) {
        Page<CoursesDO> page = new Page<CoursesDO>(request.getCurrent(),request.getSize());
        Page<CoursesDO> list = this.selectPage(page,new EntityWrapper<CoursesDO>()
                .eq(Objects.nonNull(request.getIsDeleted()),"is_deleted", request.getIsDeleted())
                .eq(Objects.nonNull(request.getCreaterId()),"creater_id", request.getCreaterId())
                .eq(Objects.nonNull(request.getNewType()),"new_type", request.getNewType())
                .eq(Objects.nonNull(request.getState()),"state", request.getState())
                .like(StringUtil.notEmpty(request.getName()),"name", request.getName())
                .eq(Objects.nonNull(request.getPublicity()),"publicity", request.getPublicity())
                .orderBy(true,"update_date",true));
        if(list.getRecords().isEmpty()){
            return Result.ok(page);
        }
        list.setRecords(list.getRecords().stream().sorted(Comparator.comparing(CoursesDO::getSort,Comparator.nullsFirst(Integer::compareTo).reversed())).collect(Collectors.toList()));
        //章节数量
        List<ChapterDO> documents =  chapterService.selectList(new EntityWrapper<ChapterDO>());
        if(!documents.isEmpty()){
            list.getRecords().forEach(a ->{
                a.setChapterNum(documents.stream().filter(b -> a.getId().equals(b.getCoursesId()) && b.getIsRoot() == 1).count());
            });
        }
        //创建人姓名
        List<UserDO> userDOS =  userService.selectList(new EntityWrapper<UserDO>());
        list.getRecords().forEach(a -> userDOS.forEach(b ->{
            if(Objects.equals(a.getCreaterId(),b.getId())){
                a.setCreaterName(b.getName());
            }
        }));
        return Result.ok(page);
    }

    /**
     * 课程编码分页查询
     * @param number
     * @return
     */
    @Override
    public Result<Page<CoursesDO>> courseNumberList(String number,Page<CoursesDO> page){

        EntityWrapper<CoursesDO> coursesDOEntityWrapper = new EntityWrapper<>();
        coursesDOEntityWrapper.eq("is_deleted", 0);
        coursesDOEntityWrapper.eq("publicity", 0);
        if(StringUtil.notEmpty(number)){
            coursesDOEntityWrapper.andNew().like("name", number).or().like("assets_id", number);
        }
        coursesDOEntityWrapper.orderBy(true,"code_mode_date",true);


        return Result.ok(this.selectPage(page,coursesDOEntityWrapper));
    }

    /**
     * 修改课程编码
     * @param course
     * @return
     */
    @Override
    public Result<String> updateCourseNumber(CoursesDO course){
        course.setCodeModeDate(new Date());
        baseMapper.update(course,new EntityWrapper<CoursesDO>().eq("id",course.getId()));
        return Result.ok();
    }


    @Override
    public Result resourceEfficiency(Long coursesId) {
        //获取章节信息
        List<ChapterDO> list =  chapterService.selectList(new EntityWrapper<ChapterDO>().eq("courses_id",coursesId));
        if(list.isEmpty()){
            return Result.fail("没有可下载的资源");
        }
        //根据资源id查询章节文件信息
        List<ChapterDocument> documents =  chapterDocumentService.selectList(new EntityWrapper<ChapterDocument>()
                .eq("courses_id",coursesId));
        if(documents.isEmpty()) {
            return Result.fail("没有可下载的资源");
        }
        return Result.ok();
    }


    @Override
    public Result fileDownload(Long coursesId,HttpServletResponse response) throws IOException {
        //获取资源名称
        String baName = this.selectById(coursesId).getName();
        //获取章节信息
        List<ChapterDO> list =  chapterService.selectList(new EntityWrapper<ChapterDO>().eq("courses_id",coursesId));
        //根据资源id查询章节文件信息
        List<ChapterDocument> documents = chapterDocumentService.selectList(new EntityWrapper<ChapterDocument>()
                .eq("courses_id",coursesId));
        //添加下载记录
        List<Records> res = recordsService.selectList(new EntityWrapper<Records>().eq("movement",1));
        res.forEach(a -> {
            Integer o = Math.toIntExact(documents.stream().filter(b -> b.getType().equals(a.getType())).count());
            a.setFrequency(a.getFrequency()+o);
        });
        recordsService.updateBatchById(res);

        //给章节匹配资源信息
        list.forEach(a ->{
            a.setChapterDocuments(documents.stream().filter(b-> b.getChapterId().equals(a.getId())).collect(Collectors.toList()));
        });
        //筛选出根目录章节信息
        List<ChapterDO>  isRootList = list.stream().filter(a -> a.getIsRoot()==1).collect(Collectors.toList());
        //筛选出非根目录章节,第一层子节点信息
        List<ChapterDO>  notRootList1 = list.stream().filter(a -> a.getLevel() == 1).collect(Collectors.toList());
        //筛选出非根目录章节,第二层子节点信息
        List<ChapterDO>  notRootList2 = list.stream().filter(a -> a.getLevel() == 2).collect(Collectors.toList());
        //匹配二层数据至一层
        notRootList1.forEach(a -> {
            a.setChapterDOS(notRootList2.stream().filter(b -> b.getParentId().equals(a.getId())).collect(Collectors.toList()));
        });
        //匹配一层数据 至根节点
        isRootList.forEach(a ->{
            a.setChapterDOS(notRootList1.stream().filter(b -> b.getParentId().equals(a.getId())).collect(Collectors.toList()));
        });
        Map<String, String> map =new HashMap<>();
        map.put("type","foundZip");
        map.put("name","foundZip");
        String foundZip = dictService.selDicBy(map);
        //获取压缩文件
        File file =  unzip(isRootList,foundZip,baName);
        //调用文件接口
        return Result.ok(foundZip(file,response));
    }



    @Override
    @Transactional
    public Result removeById(Long id) {
        //删除资源
        this.deleteById(id);
        //删除章节
        chapterService.delete(new EntityWrapper<ChapterDO>().eq("courses_id",id));
        //删除资源
        chapterDocumentService.delete(new EntityWrapper<ChapterDocument>().eq("courses_id",id));
        return Result.ok();
    }

    @Override
    public int updateBrowseNumberById(String id) {
        return this.baseMapper.updateBrowseNumberById(id);
    }


    /**
     * 门户首页查询
     * @param queryParam
     * @return
     */
    @Override
    public Page<CoursesDO> indexSearch(String queryParam,Integer current, Integer size) {
        Page<CoursesDO> page = new Page<CoursesDO>(current, size);
        //查询课程
        EntityWrapper<CoursesDO> wrapper = new EntityWrapper<>();
        wrapper.eq("state",0);
        wrapper.eq("publicity",0);
        wrapper.eq("is_deleted",0);
        wrapper.like("name", queryParam).or().like("cou_introduce", queryParam);
        List<CoursesDO> list = this.selectList(wrapper);
        if (!list.isEmpty()) {
            for (CoursesDO coursesDO : list) {
                CoursesDO search = getSearch(coursesDO.getNewType(), coursesDO.getName(), coursesDO.getCouIntroduce(), queryParam);
                coursesDO.setName(search.getName());
                coursesDO.setCouIntroduce(search.getCouIntroduce());
            }
        }
        //查询新闻
        EntityWrapper<ConsultationsDO> wrapper1 = new EntityWrapper<>();
        wrapper1.like("title", queryParam).or().like("contents", queryParam);
        wrapper1.eq("first_column","证书考试门户");
        wrapper1.eq("second_column","政策信息");
        List<ConsultationsDO> list2 = consultationsService.selectList(wrapper1);
        if (!list2.isEmpty()) {
            for (ConsultationsDO consultationsDO : list2) {
                //去除h5标签
                String htmlText = this.getHtmlText(consultationsDO.getContents());
                if(htmlText.contains(queryParam) || consultationsDO.getTitle().contains(queryParam)){
                    CoursesDO search = getSearch(3, consultationsDO.getTitle(), htmlText, queryParam);
                    search.setCreaterDate(consultationsDO.getCreaterDate());
                    search.setId(consultationsDO.getId());
                    list.add(search);
                }
            }
        }
        //排序
        if (!list.isEmpty()) {
            Collections.sort(list, new Comparator<CoursesDO>() {
                @Override
                public int compare(CoursesDO o1, CoursesDO o2) {
                     return o2.getCreaterDate().compareTo(o1.getCreaterDate());
                }
            });
        }
        page.setRecords(list);
        page.setTotal(list.size());
        return page;
    }

    /**
     * 去除富文本后元素，只留下文本
     * @param html
     * @return
     */
    public String getHtmlText(String html) {
        Document document = Jsoup.parse(html);
        Element body = document.body();
        return body.text();
    }
    /**
     * 获取关键字并且高亮显示
     * @param newType 类型 目前暂定   1.精品课程 2.自建课程 3.新闻动态
     * @param name 标题
     * @param couIntroduce 内容
     * @param queryParam 查询的关键字
     * @return
     */
    public CoursesDO getSearch(Integer newType,String name,String couIntroduce,String queryParam){
        CoursesDO coursesDO = new CoursesDO();
        coursesDO.setNewType(newType);
        //作为查询条件的关键字要高亮显示
        if(name.contains(queryParam)){
            coursesDO.setName(name.replaceAll(queryParam, "<span style='color: rgb(246, 93, 142)'>" + queryParam + "</span>"));
        }else {
            coursesDO.setName(name);
        }
        if(couIntroduce.contains(queryParam)){
            int index = couIntroduce.indexOf(queryParam);
            if (index != -1) {
                String substring = couIntroduce.substring(index + queryParam.length(), Math.min(index + queryParam.length() + 10, couIntroduce.length()));
                String result = queryParam + substring;
                coursesDO.setCouIntroduce(result.replaceAll(queryParam,"<span style='color: rgb(246, 93, 142)'>" + queryParam + "</span>"));
            }
        }else {
            coursesDO.setCouIntroduce(couIntroduce.substring(0, Math.min(couIntroduce.length(), 10)));
        }

        return coursesDO;
    }



    /**
     * 拼接节点文件
     * @param chapterDOS
     * @param foundZip
     * @param baName
     * @return
     * @throws IOException
     */
    private File unzip(List<ChapterDO> chapterDOS,String foundZip,String baName) throws IOException{
        //创建资源临时文件夹
        File file = new File(foundZip + File.separator +baName);
        boolean zeroFile = file.mkdir();
        if(zeroFile){
            //创建根目录文件夹
            for (int i = 0; i < chapterDOS.size(); i++) {
                File file1 = new File(foundZip + File.separator+baName+ File.separator+chapterDOS.get(i).getName());
                file1.mkdir();
                //写入根目录文件
                fileWrite(file1.getPath(),chapterDOS.get(i).getChapterDocuments());
                //创建一级目录
                for (int j = 0; j < chapterDOS.get(i).getChapterDOS().size(); j++) {
                    File file2 = new File(foundZip + File.separator+baName+ File.separator+chapterDOS.get(i).getName()+File.separator+chapterDOS.get(i).getChapterDOS().get(j).getName());
                    file2.mkdir();
                    //写入一级目录文件
                    fileWrite(file2.getPath(),chapterDOS.get(i).getChapterDOS().get(j).getChapterDocuments());
                    for (int k = 0; k < chapterDOS.get(i).getChapterDOS().get(j).getChapterDOS().size(); k++) {
                        File file3 = new File(foundZip + File.separator+baName+ File.separator+chapterDOS.get(i).getName()+File.separator+chapterDOS.get(i).getChapterDOS().get(j).getName()+File.separator+chapterDOS.get(i).getChapterDOS().get(j).getChapterDOS().get(k).getName());
                        file3.mkdir();
                        //写入一级目录文件
                        fileWrite(file3.getPath(),chapterDOS.get(i).getChapterDOS().get(j).getChapterDOS().get(k).getChapterDocuments());
                    }
                }
            }
        }
        return file;
    }


    /**
     * 用文件流的形式写入文件
     * @param path
     * @param chapterDocuments
     * @throws IOException
     */
    private void fileWrite(String path,List<ChapterDocument> chapterDocuments) throws IOException {
        for (int i = 0; i < chapterDocuments.size(); i++) {
            URL url = new URL(chapterDocuments.get(i).getFile());
            String[] strings =  url.getFile().split("/");
            String fileName = strings[strings.length-1];
            System.out.println(fileName);
            URLConnection conn = url.openConnection();
            // 从连接中获取输入流
            InputStream in = conn.getInputStream();
            File tempFile = new File(path,fileName);
            // 创建一个输出流，将映像写入临时文件
            FileOutputStream out = new FileOutputStream(tempFile);
            // 从输入流中读取文件并将其写入输出流
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            // 关闭输入和输出流
            in.close();
            out.close();
        }
    }


    /**
     * 封装文件接口
     */
    private byte[] foundZip(File files,HttpServletResponse response) throws IOException {
        byte[] bytes = new byte[1024];
        try {
            List<File> file = new ArrayList<>();
            String fileName = files.getPath();
            file.add(files);
            fileName = fileName + ".zip";
            System.out.println("Downloaded Zip saved as"+fileName);
            //压缩文件
            ZipFileUtils.generateZip(new File(fileName), file, false);
            File filess = new File(fileName);
            //上传成功后删除临时文件
            ZipFileUtils.download(filess,response);
            deleteFileByIO(filess.getPath());
            deleteFileByIO(files.getPath());
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            deleteFileByIO(files.getPath());
        }

        return bytes;
    }



    /**
     * 通过递归逐层删除文件信息
     *
     * @param filePath
     */
    public static void deleteFileByIO(String filePath) {
        File file = new File(filePath);
        File[] list = file.listFiles();
        if (list != null) {
            for (File temp : list) {
                deleteFileByIO(temp.getAbsolutePath());
            }
        }
        file.delete();
    }

}
